Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Value objects (Based on #634) #835

Merged
merged 33 commits into from
Feb 8, 2014
Merged

Conversation

schmittjoh
Copy link
Member

This is PR #634 with the following additional changes:

  • Merged into master (fixed some conflict in Metadata classes)
  • Support for DQL queries on fields of embedded objects

@doctrinebot
Copy link

Hello,

thank you for creating this pull request. I have automatically opened an issue
on our Jira Bug Tracker for you. See the issue link:

http://www.doctrine-project.org/jira/browse/DDC-2773

We use Jira to track the state of pull requests and the versions they got
included in.

$fieldMapping['declaredField'] = $property;
$fieldMapping['originalField'] = $fieldMapping['fieldName'];
$fieldMapping['fieldName'] = $property . "." . $fieldMapping['fieldName'];
$fieldMapping['columnName'] = $property . "_" . $fieldMapping['columnName'];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This probably needs to be delegated to the strategy handling automatic column generation instead of doing it inline here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean as an additional method?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No Doctrine\ORM\Mapping\NamingStrategy handles automatic naming of columns based on class and field names. However changing the interface is obviously a BC break. I think its small enough and easy enough to handle to make it, we need a mention in UPGRADE file though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

On Fri, Nov 1, 2013 at 9:33 PM, Benjamin Eberlei
notifications@github.51.alwrote:

In lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php:

  •    $this->embeddedClasses[$mapping['fieldName']] = $this->fullyQualifiedClassName($mapping['class']);
    
  • }
  • /**
  • \* Inline the embeddable class
    
  • *
    
  • \* @param string $property
    
  • \* @param ClassMetadataInfo $embeddable
    
  • */
    
  • public function inlineEmbeddable($property, ClassMetadataInfo $embeddable)
  • {
  •    foreach ($embeddable->fieldMappings as $fieldMapping) {
    
  •        $fieldMapping['declaredField'] = $property;
    
  •        $fieldMapping['originalField'] = $fieldMapping['fieldName'];
    
  •        $fieldMapping['fieldName'] = $property . "." . $fieldMapping['fieldName'];
    
  •        $fieldMapping['columnName'] = $property . "_" . $fieldMapping['columnName'];
    

No Doctrine\ORM\Mapping\NamingStrategy handles automatic naming of
columns based on class and field names. However changing the interface is
obviously a BC break. I think its small enough and easy enough to handle to
make it, we need a mention in UPGRADE file though.


Reply to this email directly or view it on GitHubhttps://github.com//pull/835/files#r7380794
.

*
* @return string
*/
function embeddedFieldToColumnName($propertyName, $embeddedColumnName);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to have $entityClass and $embeddedClass

$embeddedObject = $this->parentProperty->getValue($object);

if ($embeddedObject === null) {
$embeddedObject = new $this->class; // TODO
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about changing this to use the unserialize trick, or did you have something else in mind?

@beberlei
Copy link
Member

@guilhermeblanco Feedback please, this is mergable from my POV.

@schmittjoh schmittjoh deleted the ValueObjects branch February 8, 2014 17:09
@alsar
Copy link

alsar commented Feb 8, 2014

I played around with the new functionality and encountered a problem with embeddables inside embeddables.
Is this behaviour not supported yet?

@raul782
Copy link

raul782 commented Feb 8, 2014

Thanks a lot guys.

@ghost
Copy link

ghost commented Feb 8, 2014

Finally the feature was added :) Thank you all who contributed.

Maybe we can now look forward to adding support for mapping collections of embeddable objects
http://www.doctrine-project.org/jira/browse/DDC-2826

private $childProperty;
private $class;

public function __construct($parentProperty, $childProperty, $class)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aren't these parameters missing some typehint ? As it is used as (possibly ?) ReflectionProperty afterwards...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Taluu see standing TODO in the class header`.

@beberlei
Copy link
Member

beberlei commented Feb 9, 2014

@alsar Ah yes, i have to disable doing that for now. Its not yet supported.

@beberlei
Copy link
Member

beberlei commented Feb 9, 2014

@sherifsabry20000 a collection of embeddable objects is just a @OneToMany/@ManyToOne with {"cascade":"all"}

@marcospassos
Copy link

Thanks a lot guys.

@mbadolato
Copy link

Is it possible to use, for example, Address as both an entity and an embeddable? A contrived example, that has a basis in our application.

Let's say I have an entity Client that can have multiple Addresses (physical, mailing, etc). In that case Address needs to be a collection, and a OneToMany needs to be established.

In addition, each Client has a OneToMany for Facility. A Facility has one embedded Address.

Would we have to define two things with the basically the same definition (i.e., an Address entity and Address as embeddable), or can one definition serve both purposes?

Does that make sense? Or, am I thinking about the problem in entirely the wrong way?

@Ocramius
Copy link
Member

@mbadolato an entity has an ID, an embeddable doesn't, so I don't think it makes sense here. I'd also suggest moving these discussions to the mailing list

@mbadolato
Copy link

@Ocramius Re: having an id vs not having an id: Yep, hence my question. Address cannot be used in both contexts?

@mvrhov
Copy link

mvrhov commented Feb 11, 2014

@mbadolato I thought that was possible. The use case would be an invoice and a customer associated with it. When you create an invoice almost full customer information should be persisted together with it.

@schmittjoh
Copy link
Member Author

I don't think that is possible just yet as we just have a single metadata
instance per class. We would need something like the @ElementCollection
mentioned earlier to make that work.

On Tue, Feb 11, 2014 at 11:14 AM, Miha Vrhovnik notifications@github.51.alwrote:

@mbadolato https://github.com/mbadolato I thought that was possible.
The use case would be an invoice and a customer associated with it. When
you create an invoice almost full customer information should be persisted
together with it.

Reply to this email directly or view it on GitHubhttps://github.com//pull/835#issuecomment-34741113
.

@mbadolato
Copy link

That's what I was confirming. Thanks @schmittjoh.

@mvrhov Yes that is a good example of a use case for it.

@fpaterno
Copy link

@beberlei How can you use manyToOne relation between entities and embeddable element ?
I have used manyToOne but nothing happened when i've created the database.

@Ocramius
Copy link
Member

@fpaterno please open a new issue at http://www.doctrine-project.org/jira/browse/DDC or ask on the mailing list.

@mkoubik
Copy link

mkoubik commented Mar 23, 2014

@mvrhov then you should have @Embeddable CustomerData embedded both in Customer and in Invoice.

@erik-am
Copy link

erik-am commented Jun 5, 2014

I'm quite enthousiastic about Embeddables being added to Doctrine, but it's a pity that true Value Objects, which are compared by their properties, are not supported yet.

Given a Value Object Address with properties street and house number that you can instantiate with new Address("High Street", 1).

The following is now supported:
DQL1: SELECT u FROM User u WHERE (u.address.street = :street AND u.address.nr = :number) with { 'street' => 'High Street', 'number' => 1 }.

But then you should know the internal properties when writing your query. That's not how Value Objects usually are compared.

Instead, I expect to be able to do this:
DQL2: SELECT u FROM User u WHERE (u.address = :address) with { 'address' => new Address("High Street", 1) }.
Internally, DQL2 could simply be transformed to the equivalent DQL1 by replacing the condition with conditions for each internal property. The advantage is that the one writing the query does not have to refer to the internal fields; the transformation is hidden.

A complicating factor is that Value Objects are Embeddables, but not every Embeddable is a Value Object. So there is always the question if objects need to be compared by reference or by their properties.

So, perhaps it's an idea to introduce a special operator ~ for comparing objects by their value to make the distinction explicit? Like so:
DQL3: SELECT u FROM User u WHERE (u.address ~ :address) with { 'address' => new Address("High Street", 1) }.

Finally, for those who would also like more support for Value Objects, please check out my pull request for Collections. It expresses the same ideas for in-memory collections and adds the ~ operator for criterias.

Just some thoughts and ideas. I'd love to hear some discussion on this as I think it would make Doctrine really powerful in supporting rich, expressive domain models.

@stof
Copy link
Member

stof commented Jun 5, 2014

please open a ticket in the issue tracker for this feature request rather than commenting on a merged PR. Otherwise the discussion will get lost

@mkoubik
Copy link

mkoubik commented Jun 5, 2014

@erik-am 👍

@erik-am
Copy link

erik-am commented Jun 5, 2014

@stof Thanks for pointing me to the right direction. I created an issue for it: http://www.doctrine-project.org/jira/browse/DDC-3154

@mbadolato
Copy link

This thread would probably be a good candidate for the new Github Conversation Lock

@Ocramius
Copy link
Member

@mbadolato I don't see any fights going on, though yes, if anyone else has anything to add, please do so with a new issue on our issue tracker at http://www.doctrine-project.org/jira/ or on the mailing list at https://groups.google.com/forum/#!search/doctrine-user

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.